﻿using Microsoft.Xaml.Interactivity;
using System;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Codeplex.PrismAdapter
{
    /// <summary>
    /// NavigationHelperBehavior add VisualStateAwarePage's features to plain Page object.<br/>
    /// Important: This class assumes that Window.Current.Content is Frame.
    /// </summary>
    [TypeConstraint(typeof(Page))]
    public class NavigationHelperBehavior : DependencyObject, IBehavior
    {
        private Page Page { get; set; }

        private static Lazy<Frame> rootFrame = new Lazy<Frame>(() => (Frame)Window.Current.Content);

        private static Frame RootFrame
        {
            get
            {
                return rootFrame.Value;
            }
        }

        private NavigationHelper navigationHelper;

        public DependencyObject AssociatedObject
        {
            get { return this.Page; }
        }

        /// <summary>
        /// GoBack navigation history.
        /// </summary>
        public ICommand GoBackCommand { get { return this.navigationHelper.GoBackCommand; } }

        /// <summary>
        /// Page state restore event.
        /// </summary>
        public event EventHandler<LoadStateEventArgs> LoadState;

        /// <summary>
        /// Page state store event.
        /// </summary>
        public event EventHandler<SaveStateEventArgs> SaveState;

        public void Attach(DependencyObject associatedObject)
        {
            this.Page = (Page)associatedObject;

            // connect to NavigationHelper
            this.navigationHelper = new NavigationHelper(this.Page);
            this.navigationHelper.LoadState += navigationHelper_LoadState;
            this.navigationHelper.SaveState += navigationHelper_SaveState;

            RootFrame.Navigated += this.Frame_Navigated;
        }

        private void Frame_Navigated(object sender, NavigationEventArgs e)
        {
            if (e.SourcePageType == this.Page.GetType())
            {
                this.navigationHelper.OnNavigatedTo(e);
            }
            else
            {
                this.navigationHelper.OnNavigatedFrom(e);
                RootFrame.Navigated -= this.Frame_Navigated;
            }
        }

        private void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
        {
            var h = this.SaveState;
            if (h != null)
            {
                h(this, e);
            }
        }

        private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
            var h = this.LoadState;
            if (h != null)
            {
                h(this, e);
            }
        }

        public void Detach()
        {
            RootFrame.Navigated -= this.Frame_Navigated;
        }
    }
}
